﻿using Application.Utils;
using Infrastructure.Extension;
using Infrastructure.Utils;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Neoit.Utils.Extensions;
using System.Net;

namespace Web.Middlewares
{
    public class AuthFilter : Attribute, IAuthorizationFilter
    {
        private readonly IHttpContextAccessor _contextAccessor;
        private readonly TokenBuilder _tokenBuilder;
        private readonly Accessor _accessor;
        private readonly IMenuService _menuService;
        public AuthFilter(TokenBuilder tokenBuilder, Accessor accessor, IHttpContextAccessor contextAccessor, IMenuService menuService)
        {
            _tokenBuilder = tokenBuilder;
            _accessor = accessor;
            _contextAccessor = contextAccessor;
            _menuService = menuService;
        }
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var sd = _contextAccessor.HttpContext.Connection.RemoteIpAddress;
            if (AllowAnonymous(context)) return;
            //context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            //context.Result = new JsonResult(new { Msg = "测试", Code = HttpStatusCode.Unauthorized });
            //return;
            #region 持Key端
            //用于定时任务接口、其他等无登录接口
            var auth_key = context.HttpContext.Request.Headers["auth_key"].ToString();

            #endregion

            #region 验证token
            var token = context.HttpContext.Request.Headers["Authorization"].ToString();
            //无token
            if (!token.Has())
            {
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Result = new JsonResult(new { Msg = "请求缺失token", Code = HttpStatusCode.Unauthorized });
                return;
            }
            //单终端登录、token退出、主动失效之前token：结合redis使用userId:token记录并对比
            //拒绝refresh_token
            var payLoad = TokenBuilder.GetPayLoad(token);
            if (payLoad == null)
            {
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Result = new JsonResult(new { Msg = "无效的token格式", Code = HttpStatusCode.Unauthorized });
                return;
            }
            var token_type = Convert.ToString(payLoad.GetValue("token_type"));//refresh_token
            if (token_type == "refresh_token")
            {
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Result = new JsonResult(new { Msg = "非法使用refresh_token", Code = HttpStatusCode.Unauthorized });
                return;
            }

            //token过期
            var tokenExpSeccond = _tokenBuilder.ExpSeccond(token);
            if (tokenExpSeccond >= 0)
            {
                var refresh_token_limit_minute = Convert.ToInt32(payLoad.GetValue("refresh_token_limit_minute"));
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                if (tokenExpSeccond > refresh_token_limit_minute * 60)
                {
                    context.Result = new JsonResult(new { Msg = "登录token已过期", Code = 4011 });
                }
                else
                {
                    context.Result = new JsonResult(new { Msg = "登录token已过期,请刷新token", Code = 4012 });
                }
                return;
            }
            //token验证失败
            if (!_tokenBuilder.Verify(token))
            {
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Result = new JsonResult(new { Msg = "权限验证失败", Code = HttpStatusCode.Unauthorized });
                return;
            }
            _accessor.ManagerId = Convert.ToInt32(payLoad.GetValue("id"));
            _accessor.ManagerName = Convert.ToString(payLoad.GetValue("name"));
            _accessor.RoleKey = Convert.ToString(payLoad.GetValue("roleId"));
            #endregion

            #region 角色接口权限
            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            var isAnonymousRole = actionDescriptor.MethodInfo.IsDefined(typeof(AnonymousRole), true);
            if (isAnonymousRole) return;

            var roleMenus = _menuService.GetMenuListByRoleKey().GetAwaiter().GetResult();
            var action = $"{actionDescriptor.ControllerName}/{actionDescriptor.ActionName}".ToLower();
            if (!roleMenus.Any(s => s.Path.ToLower() == action))
            {
                context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Result = new JsonResult(new { Msg = "暂无该功能权限", Code = HttpStatusCode.Unauthorized });
                return;
            }
            #endregion

        }
        private static bool AllowAnonymous(AuthorizationFilterContext context)
        {
            var filters = context.Filters;
            if (filters.OfType<IAllowAnonymousFilter>().Any()) return true;
            var endpoint = context.HttpContext.GetEndpoint();
            return endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null;
        }

    }
    /// <summary>
    /// 匿名角色
    /// </summary>
    public class AnonymousRole : Attribute
    {
        public AnonymousRole()
        {
        }
    }
}
